#include "gd32f4xx_it.h"
#include "systick.h"
#include "cmsis_os.h"
#include "main.h"

#include "freertos_vars.h"
#include <stdbool.h>


typedef void (*ADC_handler_t)(uint32_t* adc_periph, bool injected);
void ADC_IRQ_Dispatch(uint32_t adc_periph,ADC_handler_t callback);

typedef void (*TIM_capture_callback_t)(uint8_t m0_m1,int channel, uint32_t timestamp);
void decode_tim_capture(uint32_t timer_periph, TIM_capture_callback_t callback,uint8_t m0_m1);

void pwm_trig_adc_cb(uint32_t adc_periph, bool injected);
void vbus_sense_adc_cb(uint32_t adc_periph, bool injected);
void tim_update_cb(uint32_t timer_periph);
void pwm_in_enc_cb(uint8_t m0_m1,int channel, uint32_t timestamp);

extern usb_core_driver cdc_acm;

/*!
    \brief      this function handles NMI exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void NMI_Handler(void)
{
    //gpio_bit_toggle(GPIOA,GPIO_PIN_15);
}

/*!
    \brief      this function handles HardFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void HardFault_Handler(void)
{
    /* if Hard Fault exception occurs, go to infinite loop */
    while (1){
        //gpio_bit_toggle(GPIOA,GPIO_PIN_15);
    }
}

/*!
    \brief      this function handles MemManage exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void MemManage_Handler(void)
{
    /* if Memory Manage exception occurs, go to infinite loop */
    while (1){
        //gpio_bit_toggle(GPIOA,GPIO_PIN_15);
    }
}

/*!
    \brief      this function handles BusFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void BusFault_Handler(void)
{
    /* if Bus Fault exception occurs, go to infinite loop */
    while (1){
        //gpio_bit_toggle(GPIOA,GPIO_PIN_15);
    }
}

/*!
    \brief      this function handles UsageFault exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void UsageFault_Handler(void)
{
    /* if Usage Fault exception occurs, go to infinite loop */
    while (1){
        //gpio_bit_toggle(GPIOA,GPIO_PIN_15);
    }
}

/*!
    \brief      this function handles SVC exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
/* void SVC_Handler(void)
{
}  */

/*!
    \brief      this function handles DebugMon exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DebugMon_Handler(void)
{

}

/*!
    \brief      this function handles PendSV exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
/* void PendSV_Handler(void)
{
} */

/*!
    \brief      this function handles SysTick exception
    \param[in]  none
    \param[out] none
    \retval     none
*/
void SysTick_Handler(void)
{
    //gpio_bit_toggle(GPIOC,GPIO_PIN_15);
    osSystickHandler();
}

void TIMER0_UP_TIMER9_IRQHandler(void){
    if(timer_interrupt_flag_get(TIMER0,TIMER_INT_FLAG_UP)==SET){
        timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_UP);
        tim_update_cb(TIMER0);
        return;
    }
    if(timer_interrupt_flag_get(TIMER0,TIMER_INT_FLAG_TRG)==SET){
        timer_interrupt_flag_clear(TIMER0,TIMER_INT_FLAG_TRG);
        return;
    }
}

void TIMER0_BRK_TIMER8_IRQHandler(void){
        decode_tim_capture(TIMER8,&pwm_in_enc_cb,2);
}

void TIMER4_IRQHandler(void){
    decode_tim_capture(TIMER4,&pwm_in_enc_cb,1);
}

void TIMER7_UP_TIMER12_IRQHandler(void){
    if(timer_interrupt_flag_get(TIMER7,TIMER_INT_FLAG_UP)==SET){
        timer_interrupt_flag_clear(TIMER7,TIMER_INT_FLAG_UP);
        tim_update_cb(TIMER7);
        return;
    }
    if(timer_interrupt_flag_get(TIMER7,TIMER_INT_FLAG_TRG)==SET){
        timer_interrupt_flag_clear(TIMER7,TIMER_INT_FLAG_TRG);
        return;
    }
}


void TIMER7_TRG_CMT_TIMER13_IRQHandler(void){
    if(timer_interrupt_flag_get(TIMER13,TIMER_INT_FLAG_UP)==SET){
        timer_interrupt_flag_clear(TIMER13,TIMER_INT_FLAG_UP);
        delay_decrement();
    }
}


void ADC_IRQHandler(void){
    ADC_IRQ_Dispatch(ADC0, &vbus_sense_adc_cb);
    ADC_IRQ_Dispatch(ADC1, &pwm_trig_adc_cb);
    ADC_IRQ_Dispatch(ADC2, &pwm_trig_adc_cb);
}


void DMA1_Channel0_IRQHandler(void){
    dma_interrupt_flag_clear(DMA1,DMA_CH0,DMA_CHXCTL_FTFIE);
}

void CAN0_RX0_IRQHandler(void){
    if((CAN_RFIFO0(CAN0)&0x03)>0){
        can_interrupt_disable(CAN0,CAN_INT_RFNE0);
        osSemaphoreRelease(sem_can); 
    }
}

void USBFS_IRQHandler(void)
{
    usbd_isr(&cdc_acm);
}



void ADC_IRQ_Dispatch(uint32_t adc_periph,ADC_handler_t callback){
    uint32_t EOIC = (ADC_STAT_EOIC) & (ADC_STAT(adc_periph)); 
    uint32_t EOIC_IT_EN = (ADC_CTL0_EOICIE) & (ADC_CTL0(adc_periph));
    uint32_t EOC = (ADC_STAT_EOC) & (ADC_STAT(adc_periph)); 
    uint32_t EOC_IT_EN = (ADC_CTL0_EOCIE) & (ADC_CTL0(adc_periph));
    if (EOIC_IT_EN && EOIC) {      // Injected measurements
        adc_interrupt_flag_clear(adc_periph,ADC_STAT_EOIC);
        adc_interrupt_flag_clear(adc_periph,ADC_STAT_EOC);
        callback(adc_periph, true);
    }
    else if (EOC_IT_EN && EOC) {       // Regular measurements
        adc_interrupt_flag_clear(adc_periph,ADC_STAT_EOC);
        callback(adc_periph, false);
    }
}


void decode_tim_capture(uint32_t timer_periph, TIM_capture_callback_t callback,uint8_t m0_m1) {
  if(timer_interrupt_flag_get(timer_periph, TIMER_INT_FLAG_CH0)) {
    timer_interrupt_flag_clear(timer_periph, TIMER_INT_FLAG_CH0);
    callback(m0_m1, 1, TIMER_CH0CV(timer_periph));
  }
  if(timer_interrupt_flag_get(timer_periph, TIMER_INT_FLAG_CH1)) {
    timer_interrupt_flag_clear(timer_periph, TIMER_INT_FLAG_CH1);
    callback(m0_m1, 2, TIMER_CH1CV(timer_periph));
  }
  if(timer_interrupt_flag_get(timer_periph, TIMER_INT_FLAG_CH2)) {
    timer_interrupt_flag_clear(timer_periph, TIMER_INT_FLAG_CH2);
    callback(m0_m1, 3, TIMER_CH2CV(timer_periph));
  }
  if(timer_interrupt_flag_get(timer_periph, TIMER_INT_FLAG_CH3)) {
    timer_interrupt_flag_clear(timer_periph, TIMER_INT_FLAG_CH3);
    callback(m0_m1, 4, TIMER_CH3CV(timer_periph));
  }
}
